#ifndef __WM_DMA_H__
#define __WM_DMA_H__

#include "wm_type_def.h"
#include "wm_regs.h"

typedef enum
{
	HAL_DMA_STATE_RESET		= 0x00U,
	
	HAL_DMA_STATE_READY		= 0x01U,
	HAL_DMA_STATE_BUSY		= 0x02U,
	HAL_DMA_STATE_TIMEOUT	= 0x03U
}HAL_DMA_StateTypeDef;

typedef struct
{
	uint32_t Direction;				/* 	Specifies if the data will be transferred from memory to peripheral,
										from peripheral to memory or from memmory to memory.
										This parameter can be a value of @ref DMA_DATA_TRANSFER_DIRECTION*/
	
	uint32_t DestInc;				/*  Specifies weather the destination address should be incremented or not.
	  									When mode is DMA_MODE_NORMAL_CIRCULAR and destination address need increment,
										must choose DMA_DINC_CIRCULAR.
	  									This parameter can be a value of @ref DMA_DEST_ADDR_INCREMENT*/
	
	uint32_t SrcInc;				/* 	Specifies weather the source address should be incremented or not.
	  									When mode is DMA_MODE_NORMAL_CIRCULAR and Source address need increment,
										must choose DMA_SINC_CIRCULAR.
	  									This parameter can be a value of @ref DMA_SRC_ADDR_INCREMENT*/
	
	uint32_t DataAlignment;			/*  Specifies the transport unit.
	  									This parameter can be a value of @ref DMA_DATAALIGN*/
	
	uint32_t Mode;					/*  Specifies the operation mode of the DMA channelx. When you need to 
	  									use half-complete interrupts, you must use link mode.
	  									This parameter can be a value of @ref DMA_MODE*/
	
	uint32_t RequestSourceSel;		/*  Specifies the request source of DMA.
										This parameter can be a value of @ref DMA_REQUEST_SOURCE*/

    uint32_t RequestUartSel;		/*  Specifies the UART number when the RequestSourceSel is DMA_REQUEST_SOURCE_UART_RX
									    or DMA_REQUEST_SOURCE_UART_TX. This parameter can be a value of @ref DMA_UART_CHANNEL_SEL*/
										
} DMA_InitTypeDef;

/* The descriptor structure is used internally by the driver layer,
   and the user layer does not need to be assigned. */
typedef struct __DMA_LinkDescriptor
{
	uint32_t Valid;					/*  According to the Bit31 to indicate whether the data pointed to by the 
										descriptor is valid. Bit31 equal to 1 means valid, equal to 0 means invalid */
	
	uint32_t Control;				/*  Equal to the value of register CR2[23:1] */
	
	uint32_t SrcAddr;				/*  Data source address */
	
	uint32_t DestAddr;				/*  Data destinathion address */
	
	struct __DMA_LinkDescriptor *Next;	/*	Point to the address of the next descriptor structure */
	
} DMA_LinkDescriptor;

typedef enum
{
	HAL_DMA_HALF_TRANSFER = 0,
	HAL_DMA_FULL_TRANSFER = 1
} HAL_DMA_LevelCompleteTypeDef;

typedef struct __DMA_HandleTypeDef
{
	DMA_Channel_TypeDef		*Instance;		/* Register base address of the channel used. 
											   Need user layer assignment.*/
	
	DMA_InitTypeDef			Init;			/* DMA communication parameters. Need user layer assignment*/
	
	HAL_LockTypeDef			Lock;			/* DMA locking object. */
	
	HAL_DMA_StateTypeDef	State;			/* DMA transfer state. */
	
	void					*Parent;		/* Parent object state. Need user layer assignment*/
	
	void					(* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /* DMA transfer complete callback. */
  
	void					(* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);	/* DMA Half transfer complete callback. */
	
	void					(* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);	/* DMA transfer abort callback. */
	
	DMA_TypeDef				*DmaBaseAddress;	/* DMA register base address. */
	
	uint32_t				ChannelIndex;		/* DMA Channel Index. */
	
	__IO uint32_t			ErrorCode;			/* DMA error code. */
	
	DMA_LinkDescriptor		*LinkDesc;			/* Points to the descriptor address. When user need to use the 
												   DMA half-completed interrupt, assign a value in the user layer.
												   E.g DMA_LinkDescriptor desc[2], Size must be 2. */
	
	uint32_t				offset;				/* For internal use, the user does not need to assign a value. */
	
} DMA_HandleTypeDef;

// DMA register base address and channel base address.
#define DMA					((DMA_TypeDef *)DMA_BASE)
#define DMA_Channel0		((DMA_Channel_TypeDef *)DMA_Channel0_BASE)
#define DMA_Channel1		((DMA_Channel_TypeDef *)DMA_Channel1_BASE)
#define DMA_Channel2		((DMA_Channel_TypeDef *)DMA_Channel2_BASE)
#define DMA_Channel3		((DMA_Channel_TypeDef *)DMA_Channel3_BASE)
#define DMA_Channel4		((DMA_Channel_TypeDef *)DMA_Channel4_BASE)
#define DMA_Channel5		((DMA_Channel_TypeDef *)DMA_Channel5_BASE)
#define DMA_Channel6		((DMA_Channel_TypeDef *)DMA_Channel6_BASE)
#define DMA_Channel7		((DMA_Channel_TypeDef *)DMA_Channel7_BASE)

// DMA Error Code
#define HAL_DMA_ERROR_NONE			0x0U	// No error
#define HAL_DMA_ERROR_NO_XFER		0x1U	// no ongoing transfer
#define HAL_DMA_ERROR_TIMEOUT		0x2U	// Timout error
#define HAL_DMA_ERROR_NOT_SUPPORTED	0x4U	// Not supported mode

// DMA_DATA_TRANSFER_DIRECTION
#define DMA_PERIPH_TO_MEMORY		((uint32_t)DMA_MODE_SHM)	// Peripheral to memory direction
#define DMA_MEMORY_TO_PERIPH		((uint32_t)DMA_MODE_SHM)	// Memory to peripheral direction
#define DMA_MEMORY_TO_MEMORY		0x00000000U					// Memory to memory direction

// DMA_DEST_ADDR_INCREMENT
#define DMA_DINC_ENABLE				((uint32_t)DMA_CR2_DINC_ENABLE)		// Destination address increment mode Enable
#define DMA_DINC_DISABLE			((uint32_t)DMA_CR2_DINC_DISABLE)	// Destination address increment mode Disable
#define DMA_DINC_CIRCULAR			((uint32_t)DMA_CR2_DINC_CYCLE)		// Destination address circular mode. Only when Mode = DMA_MODE_NORMAL_CIRCULAR

// DMA_SRC_ADDR_INCREMENT
#define DMA_SINC_ENABLE				((uint32_t)DMA_CR2_SINC_ENABLE)		// Source address increment mode Enable
#define DMA_SINC_DISABLE			((uint32_t)DMA_CR2_SINC_DISABLE)	// Source address increment mode Disable
#define DMA_SINC_CIRCULAR			((uint32_t)DMA_CR2_SINC_CYCLE)		// Source address circular mode. Only when Mode = DMA_MODE_NORMAL_CIRCULAR

// DMA_DATAALIGN
#define DMA_DATAALIGN_BYTE			((uint32_t)DMA_CR2_TRANS_SIZE_BYTE)			// Memory data alignment: Byte
#define DMA_DATAALIGN_HALFWORD		((uint32_t)DMA_CR2_TRANS_SIZE_HALFWORD)		// Memory data alignment: HalfWord
#define DMA_DATAALIGN_WORD			((uint32_t)DMA_CR2_TRANS_SIZE_WORD)			// Memory data alignment: Word

// DMA_MODE
#define DMA_MODE_NORMAL_SINGLE				0x00000000U				// Normal single mode
#define DMA_MODE_NORMAL_CIRCULAR			0x00000001U				// Normal circular mode
#define DMA_MODE_LINK_SINGLE				0x00000002U				// Link	singal mode
#define DMA_MODE_LINK_CIRCULAR				0x00000003U				// Link circular mode

// DMA_INTERRUPT_TYPE
#define DMA_FLAG_TF_DONE			DMA_IF_TRANSFER_DONE			// Transfer complete interrupt
#define DMA_FLAG_BURST_DONE			DMA_IF_BURST_DONE				// Burst complete interrupt

// DMA_REQUEST_SOURCE
#define DMA_REQUEST_SOURCE_UART_RX		DMA_MODE_CH_UART_RX
#define DMA_REQUEST_SOURCE_UART_TX		DMA_MODE_CH_UART_TX
#define DMA_REQUEST_SOURCE_PWM_CAP0		DMA_MODE_CH_PWM_CAP0
#define DMA_REQUEST_SOURCE_PWM_CAP1		DMA_MODE_CH_PWM_CAP1
#define DMA_REQUEST_SOURCE_SPI_RX		DMA_MODE_CH_LSPI_RX
#define DMA_REQUEST_SOURCE_SPI_TX		DMA_MODE_CH_LSPI_TX
#define DMA_REQUEST_SOURCE_ADC_CH0		DMA_MODE_CH_ADC0
#define DMA_REQUEST_SOURCE_ADC_CH1		DMA_MODE_CH_ADC1
#define DMA_REQUEST_SOURCE_ADC_CH2		DMA_MODE_CH_ADC2
#define DMA_REQUEST_SOURCE_ADC_CH3		DMA_MODE_CH_ADC3
#define DMA_REQUEST_SOURCE_I2S_RX		DMA_MODE_CH_I2SRX
#define DMA_REQUEST_SOURCE_I2S_TX		DMA_MODE_CH_I2STX
#define DMA_REQUEST_SOURCE_SDIO			DMA_MODE_CH_SDIO

// DMA_UART_CHANNEL_SEL
#define DMA_UART_CHANNEL_SEL_UART0		DMA_REQCH_UART0
#define DMA_UART_CHANNEL_SEL_UART1		DMA_REQCH_UART1
#define DMA_UART_CHANNEL_SEL_UART2		DMA_REQCH_UART2
#define DMA_UART_CHANNEL_SEL_UART3		DMA_REQCH_UART3
#define DMA_UART_CHANNEL_SEL_UART4		DMA_REQCH_UART4
#define DMA_UART_CHANNEL_SEL_UART5		DMA_REQCH_UART5


#define IS_DMA_ALL_INSTANCE(INSTANCE)	(((INSTANCE) == DMA_Channel0) || \
										 ((INSTANCE) == DMA_Channel1) || \
										 ((INSTANCE) == DMA_Channel2) || \
										 ((INSTANCE) == DMA_Channel3) || \
										 ((INSTANCE) == DMA_Channel4) || \
										 ((INSTANCE) == DMA_Channel5) || \
										 ((INSTANCE) == DMA_Channel6) || \
										 ((INSTANCE) == DMA_Channel7))

#define IS_DMA_DIRECTION(DIRECTION)		(((DIRECTION) == DMA_PERIPH_TO_MEMORY) || \
										 ((DIRECTION) == DMA_MEMORY_TO_PERIPH) || \
										 ((DIRECTION) == DMA_MEMORY_TO_MEMORY))
										 
#define IS_DMA_DEST_INC_STATE(STATE)	(((STATE) == DMA_DINC_ENABLE) || \
											 ((STATE) == DMA_DINC_DISABLE))
											 
#define IS_DMA_SRC_INC_STATE(STATE)		(((STATE) == DMA_SINC_ENABLE) || \
											 ((STATE) == DMA_SINC_DISABLE))
											 
#define IS_DMA_DATA_SIZE(SIZE)			(((SIZE) == DMA_DATAALIGN_BYTE) || \
										 ((SIZE) == DMA_DATAALIGN_HALFWORD) || \
										 ((SIZE) == DMA_DATAALIGN_WORD))

#define IS_DMA_MODE(MODE)				(((MODE) == DMA_MODE_NORMAL_SINGLE) || \
										 ((MODE) == DMA_MODE_NORMAL_CIRCULAR) || \
										 ((MODE) == DMA_MODE_LINK_SINGLE) || \
										 ((MODE) == DMA_MODE_LINK_CIRCULAR))
										 
#define IS_DMA_REQUEST_SOURCE(SEL)		(((SEL) == DMA_REQUEST_SOURCE_UART_RX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_UART_TX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_PWM_CAP0) || \
										 ((SEL) == DMA_REQUEST_SOURCE_PWM_CAP1) || \
										 ((SEL) == DMA_REQUEST_SOURCE_SPI_RX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_SPI_TX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_ADC_CH0) || \
										 ((SEL) == DMA_REQUEST_SOURCE_ADC_CH1) || \
										 ((SEL) == DMA_REQUEST_SOURCE_ADC_CH2) || \
										 ((SEL) == DMA_REQUEST_SOURCE_ADC_CH3) || \
										 ((SEL) == DMA_REQUEST_SOURCE_I2S_RX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_I2S_TX) || \
										 ((SEL) == DMA_REQUEST_SOURCE_SDIO))
										 
#define IS_DMA_UART_CHANNEL(CHANNEL)	(((CHANNEL) == DMA_UART_CHANNEL_SEL_UART0) || \
										 ((CHANNEL) == DMA_UART_CHANNEL_SEL_UART1) || \
										 ((CHANNEL) == DMA_UART_CHANNEL_SEL_UART2) || \
										 ((CHANNEL) == DMA_UART_CHANNEL_SEL_UART3) || \
										 ((CHANNEL) == DMA_UART_CHANNEL_SEL_UART4) || \
										 ((CHANNEL) == DMA_UART_CHANNEL_SEL_UART5))	

#define IS_DMA_BUFFER_SIZE(SIZE)		(((SIZE) >= 0x1U) && ((SIZE) < 0x10000U))

#define IS_DMA_SRC_ADDR(SRC)			(((SRC) % 4) == 0)

#define IS_DMA_DEST_ADDR(DEST)			(((DEST) % 4) == 0)

#define IS_DMA_LENGTH(DATAALIGN, LEN)	((((DATAALIGN) == DMA_DATAALIGN_BYTE) && (((LEN) % 1) == 0)) || \
										 (((DATAALIGN) == DMA_DATAALIGN_HALFWORD) && (((LEN) % 2) == 0)) || \
										 (((DATAALIGN) == DMA_DATAALIGN_WORD) && (((LEN) % 4) == 0)))

#define IS_DMA_LINK_LENGTH(LEN)			(((LINK) % 8) == 0)

#define IS_DMA_COMPLETELEVEL(LEVEL)		(((LEVEL) == HAL_DMA_HALF_TRANSFER) || ((LEVEL) = HAL_DMA_FULL_TRANSFER))

#define __HAL_DMA_ENABLE(__HANDLE__)	(SET_BIT((__HANDLE__)->Instance->CR1, DMA_CR1_START))

#define __HAL_DMA_DISABLE(__HANDLE__)	do {													 \
											SET_BIT((__HANDLE__)->Instance->CR1, DMA_CR1_STOP);  \
											while ((__HANDLE__)->Instance->CR1 & DMA_CR1_START); \
										} while (0)

#define __HAL_DMA_ENABLE_IT(__HANDLE__, __INTERRUPT__)	(CLEAR_BIT((__HANDLE__)->DmaBaseAddress->IM, (__INTERRUPT__)))

#define __HAL_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__)	(SET_BIT((__HANDLE__)->DmaBaseAddress->IM, (__INTERRUPT__)))

#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)	(((__HANDLE__)->DmaBaseAddress->IF) & (__FLAG__))

#define __HAL_DMA_CLEAR_FLAG(__HANDLE__, __FLAG__)	(SET_BIT((__HANDLE__)->DmaBaseAddress->IF, (__FLAG__)))

HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_DeInit (DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_Start (DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength);
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength);
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout);
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma);

HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef *hdma);
uint32_t HAL_DMA_GetError(DMA_HandleTypeDef *hdma);

#endif